package net.chenlin.dp.modules.drtrade.controller;

import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import net.chenlin.dp.common.annotation.SysLog;
import net.chenlin.dp.common.entity.R;
import net.chenlin.dp.common.utils.CommonUtils;
import net.chenlin.dp.common.utils.DateUtils;
import net.chenlin.dp.common.utils.IpUtils;
import net.chenlin.dp.common.utils.MD5Utils;
import net.chenlin.dp.modules.base.entity.SysAreaEntity;
import net.chenlin.dp.modules.base.entity.SysMacroEntity;
import net.chenlin.dp.modules.base.service.SysAreaService;
import net.chenlin.dp.modules.base.service.SysMacroService;
import net.chenlin.dp.modules.drtrade.entity.DrtradeMemberAddressEntity;
import net.chenlin.dp.modules.drtrade.entity.DrtradeMemberEntity;
import net.chenlin.dp.modules.drtrade.entity.DrtradeOrderEntity;
import net.chenlin.dp.modules.drtrade.service.DrtradeAgencyService;
import net.chenlin.dp.modules.drtrade.service.DrtradeMemberAddressService;
import net.chenlin.dp.modules.drtrade.service.DrtradeMemberService;
import net.chenlin.dp.modules.drtrade.service.DrtradeOrderService;
import net.chenlin.dp.modules.sys.controller.AbstractController;
import net.chenlin.dp.modules.sys.service.SysLogService;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;

/**
 * Created by thinkpad on 2018/3/21.
 */
@CrossOrigin
@RestController
@RequestMapping("api")
public class ApiController extends AbstractController {

    @Value("${wechat.mp.afterAuth}")
    private String afterAuth;

    @Value("${wechat.mp.redirectUri}")
    private String redirectUri;

    @Value("${wechat.pay.notifyUrl}")
    private String notifyUrl;

    @Value("${wechat.pay.mchKey}")
    private String mchKey;

    @Autowired
    private WxMpService wxService;

    @Resource(name = "wxPayService")
    private WxPayService wxPayService;

    @Autowired
    private DrtradeMemberService memberService;

    @Autowired
    private DrtradeAgencyService drtradeAgencyService;

    @Autowired
    private DrtradeMemberAddressService drtradeMemberAddressService;

    @Autowired
    private SysMacroService sysMacroService;

    @Autowired
    private SysLogService logService;

    @Autowired
    private DrtradeOrderService orderService;

    @Autowired
    private SysAreaService sysAreaService;

    @RequestMapping("/login")
    public R login(@RequestBody DrtradeMemberEntity member) {
        System.out.println(member.getOpenid());
        member = memberService.getByOpenid(member.getOpenid());
        if (CommonUtils.isNullOrEmpty(member)) {
            return R.error(100, wxService.oauth2buildAuthorizationUrl(
                    redirectUri, "snsapi_userinfo", "11"));
        }
        return R.ok().put("member", member);
    }

    @RequestMapping("/agencyInfo/{id}")
    public R agencyInfo(@PathVariable Long id) {
        return drtradeAgencyService.getDrtradeAgencyById(id);
    }

    @RequestMapping("/wxAuth")
    public void wxAuth(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String code = request.getParameter("code");
        WxMpOAuth2AccessToken accessToken = wxService.oauth2getAccessToken(code);
        DrtradeMemberEntity member = memberService.getByOpenid(accessToken.getOpenId());
        if (member == null) {
            WxMpUser wxMpUser = wxService.oauth2getUserInfo(accessToken, "zh_CN");
            member = new DrtradeMemberEntity();
            member.setCity(wxMpUser.getCity());
            member.setCountry(wxMpUser.getCountry());
            member.setHeadimgurl(wxMpUser.getHeadImgUrl());
            member.setNickname(wxMpUser.getNickname());
            member.setOpenid(wxMpUser.getOpenId());
            member.setSex(wxMpUser.getSex().toString());
            member.setUnionid(wxMpUser.getUnionId());
            memberService.saveDrtradeMember(member);
        }
        Cookie cookie = new Cookie("openid", accessToken.getOpenId()); //设置cookie的key和value值
        cookie.setPath("/");        //路径
        cookie.setMaxAge(24 * 60 * 60 * 30);
        response.addCookie(cookie); //添加cookie
        response.sendRedirect(afterAuth);
    }

    /**
     * 列表
     *
     * @param memberId
     * @return
     */
    @RequestMapping("/address/list/{memberId}")
    public List<DrtradeMemberAddressEntity> list(@PathVariable Integer memberId) {
        return drtradeMemberAddressService.findByMemberId(memberId);
    }

    /**
     * 新增
     *
     * @param drtradeMemberAddress
     * @return
     */
    @SysLog("新增")
    @RequestMapping("/address/save")
    public R save(@RequestBody DrtradeMemberAddressEntity drtradeMemberAddress) {
        return drtradeMemberAddressService.saveDrtradeMemberAddress(drtradeMemberAddress);
    }

    /**
     * 根据id查询详情
     *
     * @param id
     * @return
     */
    @RequestMapping("/address/info")
    public R getById(@RequestBody Long id) {
        return drtradeMemberAddressService.getDrtradeMemberAddressById(id);
    }

    /**
     * 修改
     *
     * @param drtradeMemberAddress
     * @return
     */
    @SysLog("修改")
    @RequestMapping("/address/update")
    public R update(@RequestBody DrtradeMemberAddressEntity drtradeMemberAddress) {
        return drtradeMemberAddressService.updateDrtradeMemberAddress(drtradeMemberAddress);
    }

    /**
     * 删除
     *
     * @param id
     * @return
     */
    @SysLog("删除")
    @RequestMapping("/address/remove")
    public R batchRemove(@RequestBody Long[] id) {
        return drtradeMemberAddressService.batchRemove(id);
    }

    @SysLog("获取商品数据")
    @RequestMapping("skuData")
    public R getSkuData() {
        List<SysMacroEntity> modelList = sysMacroService.findByTypeName("规格型号");
        List<SysMacroEntity> unitList = sysMacroService.findByTypeName("单位");
        List<Map<String, Object>> treeList = new ArrayList<Map<String, Object>>();
        Map<String, Object> modelMap = new HashMap<String, Object>();
        modelMap.put("k", "规格型号");
        List<Map<String, Object>> modelVLsit = new ArrayList<Map<String, Object>>();
        modelMap.put("v", modelVLsit);
        modelMap.put("k_s", "s1");
        for (SysMacroEntity model : modelList) {
            Map<String, Object> modelV = new HashMap<String, Object>();
            modelV.put("id", model.getMacroId());
            modelV.put("name", model.getName());
            modelVLsit.add(modelV);
        }
        treeList.add(modelMap);
        Map<String, Object> unitMap = new HashMap<String, Object>();
        unitMap.put("k", "单位");
        List<Map<String, Object>> unitVList = new ArrayList<Map<String, Object>>();
        unitMap.put("v", unitVList);
        for (SysMacroEntity unit : unitList) {
            Map<String, Object> unitV = new HashMap<String, Object>();
            unitV.put("id", unit.getMacroId());
            unitV.put("name", unit.getName());
            unitVList.add(unitV);
        }
        unitMap.put("k_s", "s2");
        treeList.add(unitMap);
        List<SysMacroEntity> priceList = sysMacroService.findByTypeName("商品价格");
        List<SysMacroEntity> stockList = sysMacroService.findByTypeName("商品库存");
        List<Map<String, Object>> skuList = new ArrayList<Map<String, Object>>();

        for (SysMacroEntity price : priceList) {
            String[] mu = price.getName().split("/");
            Map<String, Object> sku = new HashMap<String, Object>();
            sku.put("id", price.getMacroId());
            sku.put("price", new BigDecimal(price.getValue()).multiply(new BigDecimal(100)));
            sku.put("desc", price.getName());
            for (Map<String, Object> modelV : modelVLsit) {
                if (modelV.get("name").toString().equals(mu[0])) {
                    sku.put("s1", modelV.get("id"));
                }
            }
            for (Map<String, Object> unitV : unitVList) {
                if (unitV.get("name").toString().equals(mu[1])) {
                    sku.put("s2", unitV.get("id"));
                }
            }
            sku.put("goods_id", sku.get("s1")+"/"+sku.get("s2"));
            skuList.add(sku);
        }


        for (SysMacroEntity stock : stockList) {
            for (Map<String, Object> sku : skuList) {
                if(stock.getName().equals(sku.get("desc").toString())){
                    sku.put("stock_num", Integer.valueOf(stock.getValue()));
                }
            }
        }

        Map<String, Object> skuData = new HashMap<String, Object>();
        skuData.put("tree", treeList);
        skuData.put("list", skuList);
        skuData.put("none_sku", false);
        skuData.put("hide_stock", true);
        List<SysMacroEntity> goodAttrList = sysMacroService.findByTypeName("商品属性");
        for (SysMacroEntity attr : goodAttrList) {
            if ("默认价格".equals(attr.getName())) {
                skuData.put("price", attr.getValue());
            }
            if ("商品名称".equals(attr.getName())) {
                skuData.put("title", attr.getValue());
            }
            if ("默认库存".equals(attr.getName())) {
                skuData.put("stock_num", Integer.valueOf(attr.getValue()));
            }
        }
        return R.ok().put("skuData", skuData);
    }

    @SysLog("统一下单")
    @RequestMapping("/unifiedOrder")
    public R unifiedOrder(@RequestBody DrtradeOrderEntity order){
        //  业务逻辑 需仔细
        if(order.getOrderNo() != null){
            order = orderService.getByOrderNo(order.getOrderNo());
        }else{
            order.setStatus("0");
            order.setCreateIp(IpUtils.getIpAddr());
            order.setOrderNo(DateUtils.getOrderNumber());
            order.setCreateTime(new Date());
        }
        Map<String, Object> result = new TreeMap<String, Object>();
        WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
        request.setSpbillCreateIp(order.getCreateIp());
        request.setBody(order.getDesc());
        request.setTotalFee(order.getTotalFee().intValue());
        request.setNotifyUrl(notifyUrl);
        request.setTradeType(order.getPayType());
        request.setOpenid(order.getOpenid());
        request.setOutTradeNo(order.getOrderNo());
        try{
            WxPayUnifiedOrderResult wxResult = wxPayService.unifiedOrder(request);

            String timestamp = Long.toString(System.currentTimeMillis() / 1000);
            String pkg = "prepay_id=" + wxResult.getPrepayId();
            String str = "appId=" + wxResult.getAppid() + "&nonceStr=" + request.getNonceStr() + "&package="
                    + pkg + "&signType=MD5" + "&timeStamp=" + timestamp
            + "&key=" + mchKey;
            String paySign = DigestUtils.md5Hex(str).toUpperCase();
            result.put("appid",wxResult.getAppid());
            result.put("prepayId",wxResult.getPrepayId());
            result.put("nonceStr",request.getNonceStr());
            result.put("paySign",paySign);
            result.put("signType", "MD5");

            result.put("orderNo",order.getOrderNo());
            result.put("timeStamp", timestamp);
            if(order.getId() != null){
                order.setUpdateTime(new Date());
                orderService.updateDrtradeOrder(order);
            }else {
                orderService.saveDrtradeOrder(order);
            }
            return R.ok().put("orderResult", result);
        }catch (Exception e){
            e.printStackTrace();
            logger.error("微信支付失败！订单号：{},原因:{}", order.getOrderNo(), e.getMessage());
            return R.error(500,"微信支付失败，请稍后重试");
        }
    }

    @SysLog("微信支付回调")
    @ResponseBody
    @RequestMapping("/payNotify")
    public String payNotify(HttpServletRequest request, HttpServletResponse response) {
        try {
            String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
            WxPayOrderNotifyResult result = wxPayService.parseOrderNotifyResult(xmlResult);
            // 结果正确
            String orderNo = result.getOutTradeNo();
            String tradeNo = result.getTransactionId();
            String totalFee = BaseWxPayResult.feeToYuan(result.getTotalFee());
            //需要判断订单是否已经支付过，否则可能会重复调用
            DrtradeOrderEntity order = orderService.getByOrderNo(orderNo);
            if("0".equals(order.getStatus())){
               order.setStatus("1");
               order.setUpdateTime(new Date());
               order.setPayTime(org.apache.commons.lang3.time.DateUtils.parseDate(result.getTimeEnd(),"yyyyMMddHHmmss"));
               order.setTransactionId(result.getTransactionId());
               orderService.updateDrtradeOrder(order);
            }
            return WxPayNotifyResponse.success("处理成功!");
        } catch (Exception e) {
            logger.error("微信回调结果异常,异常原因{}", e.getMessage());
            return WxPayNotifyResponse.fail(e.getMessage());
        }
    }

    @SysLog("查询订单接口")
    @RequestMapping("findOrderByOpenid")
    public R findOrderByOpenid(@RequestBody DrtradeOrderEntity order){
        return R.ok().put("orders",orderService.findOrderByOpenid(order.getOpenid(),order.getStatus()));
    }

    @SysLog("查询订单接口")
    @RequestMapping("getOrder")
    public R getOrder(@RequestBody DrtradeOrderEntity order){
        return R.ok().put("order",orderService.getByOrderNo(order.getOrderNo()));
    }


    @SysLog("查询支付结果")
    @RequestMapping("getPayResult")
    public R getPayResult(@RequestBody DrtradeOrderEntity order){
        order = orderService.getByOrderNo(order.getOrderNo());
        if("0".equals(order.getStatus())){
            try {
                WxPayOrderQueryResult orderResult = wxPayService.queryOrder(null, order.getOrderNo());
                if(orderResult.getTradeState().equals(WxPayConstants.WxpayTradeStatus.SUCCESS)){
                    order.setStatus("1");
                    order.setUpdateTime(new Date());
                    order.setPayTime(org.apache.commons.lang3.time.DateUtils.parseDate(orderResult.getTimeEnd(),"yyyyMMddHHmmss"));
                    order.setTransactionId(orderResult.getTransactionId());
                    orderService.updateDrtradeOrder(order);
                    return R.ok().put("result", "PAY_SUCCESS");
                }else if(orderResult.getTradeState().equals(WxPayConstants.WxpayTradeStatus.NOTPAY)){
                    return R.ok().put("result", "NOTPAY");
                }else{
                    return R.ok().put("result", "PAY_FAIL");
                }
            }catch (Exception e){
                logger.error("查询微信支付订单异常,异常原因{}", e.getMessage());
                return R.ok().put("result","PAY_FAIL");
            }
        }
        return R.ok().put("result", "PAY_SUCCESS");
    }

    @SysLog("获取地市列表")
    @RequestMapping("areaList")
    public Map<String,Object> areaList(){
        Map<String, Object> result = new TreeMap<String, Object>();
        Map<String, Object> province = new TreeMap<String, Object>();
        result.put("province_list", province);
        province.put("350100","福州市");
        Map<String, Object> city_list = new TreeMap<String, Object>();
        Map<String, Object> county_list = new TreeMap<String, Object>();
        for (SysAreaEntity sysArea: sysAreaService.listAreaByParentCode("350100")) {
            city_list.put(sysArea.getAreaCode(),sysArea.getName());
            for (SysAreaEntity countryArea: sysAreaService.listAreaByParentCode(sysArea.getAreaCode())){
                county_list.put(countryArea.getAreaCode(),countryArea.getName());
            }
        }
        result.put("city_list", city_list);
        result.put("county_list", county_list);
        return result;
    }
}